package com.dayuanit.mall.bank.service.impl;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.dayuanit.mall.bank.dao.SinaOrderDao;
import com.dayuanit.mall.bank.domain.SinaNotifyResponse;
import com.dayuanit.mall.bank.domain.SinaOrder;
import com.dayuanit.mall.bank.dto.SinaPayQuery;
import com.dayuanit.mall.bank.dto.SinaPayRequest;
import com.dayuanit.mall.bank.dto.SinaPayResponse;
import com.dayuanit.mall.bank.exception.MallBusException;
import com.dayuanit.mall.bank.notify.SinaNotify;
import com.dayuanit.mall.bank.payenum.NotifyStatusEnum;
import com.dayuanit.mall.bank.payenum.PayErrorEnum;
import com.dayuanit.mall.bank.payenum.PayOrderEnum;
import com.dayuanit.mall.bank.service.SinaOrderService;
import com.dayuanit.mall.bank.util.DateUtil;

@Service
public class SinaOrderServiceImpl implements SinaOrderService {
	
	private static final Logger log = LoggerFactory.getLogger(SinaOrderService.class);
	
	@Autowired
	private SinaOrderDao sinaOrderDao;
	
	@Value("#{configProperties['dayuanit.fee']}")
	private String fee;
	
	@Value("#{configProperties['dayuanit.key']}")
	private String key;
	
	private static final String SIGN_TYPE_MD5 = "1";
	
	private static final String SIGN_TYPE_RSA = "4";
	
	@Autowired
	private SinaNotify sinaNotify;
	
	@Override
	public SinaOrder addOrder(SinaPayRequest sinaPayRequest) {
		
		//TODO 必填参数的非空验证 以及常量值的合法性验证 ...
		checkPayParam(sinaPayRequest);
		
		//是否重复提交 根据商户账号和商户订单ID
		SinaOrder so = sinaOrderDao.getOrderByMerchantIdAndOrderId(sinaPayRequest.getMerchantAcctId(), sinaPayRequest.getOrderId());
		if (null != so) {
			orderExist(so);
			return so;
		}
		
		return orderNotExist(sinaPayRequest);
	}
	
	private void checkPayParam(SinaPayRequest sinaPayRequest) {
		if (StringUtils.isBlank(sinaPayRequest.getSignMsg())) {
			throw new MallBusException(PayErrorEnum.SIGN_IS_EMPTY.getDesc(), PayErrorEnum.SIGN_IS_EMPTY.getCode());
		}
		
		if (StringUtils.isBlank(sinaPayRequest.getSignType())) {
			throw new MallBusException(PayErrorEnum.PARAM_IS_EMPTY.getDesc(), PayErrorEnum.PARAM_IS_EMPTY.getCode());
		}
		
		if (!SIGN_TYPE_MD5.equals(sinaPayRequest.getSignType()) && !SIGN_TYPE_RSA.equals(sinaPayRequest.getSignType())) {
			throw new MallBusException(PayErrorEnum.PARAM_VALUE_ERROR.getDesc(), PayErrorEnum.PARAM_VALUE_ERROR.getCode());
		}
		
		//验证签名
		String origin = sinaPayRequest.createSignOrigin(key);
		String sign = null;
				
		if (SIGN_TYPE_MD5.equals(sinaPayRequest.getSignType())) {
			sign = DigestUtils.md5Hex(origin);
		} else {
			//TODO RSA生成签名
			sign = "xxxxxxxxxxxxxxxxxx";
		}
		
		if (!sign.equals(sinaPayRequest.getSignMsg())) {
			throw new MallBusException(PayErrorEnum.SIGN_VALUE_ERROR.getDesc(), PayErrorEnum.SIGN_VALUE_ERROR.getCode());
		}
	}
	
	@Override
	@Transactional(rollbackFor=Exception.class)
	public SinaNotifyResponse sinaPay(int id, String pwd) {
		//验证支付密码
		if(StringUtils.isBlank(pwd)) {
			throw new MallBusException(PayErrorEnum.PAY_PASSWORD_ERROR.getDesc(), PayErrorEnum.PAY_PASSWORD_ERROR.getCode());
		}
		
		SinaOrder sinaOrder = sinaOrderDao.getOrderById(id);
		if (null == sinaOrder) {
			throw new MallBusException(PayErrorEnum.PAY_ORDER_INVALID.getDesc(), PayErrorEnum.PAY_ORDER_INVALID.getCode());
		}
		
		if (PayOrderEnum.ALREADY_PAID.getStatus() == sinaOrder.getStatus()) {
			throw new MallBusException(PayErrorEnum.ALREADY_PAY.getDesc(), PayErrorEnum.ALREADY_PAY.getCode());
		}
		
		if (PayOrderEnum.PAY_ING.getStatus() == sinaOrder.getStatus()) {
			throw new MallBusException(PayErrorEnum.PAY_ING.getDesc(), PayErrorEnum.PAY_ING.getCode());
		}
		
		if (PayOrderEnum.PAY_INVALID.getStatus() == sinaOrder.getStatus()) {
			throw new MallBusException(PayErrorEnum.PAY_INVALID.getDesc(), PayErrorEnum.PAY_INVALID.getCode());
		}
		
		//修改订单状态为支付中
		int rows = sinaOrderDao.updateOrderBystatus(sinaOrder.getId(), sinaOrder.getStatus(), PayOrderEnum.PAY_ING.getStatus());
		if (1 != rows) {
			log.error("商户{}订单号{}支付失败，原因：订单状态由{}转换为{}失败", sinaOrder.getMerchantId(), sinaOrder.getOrderId(), sinaOrder.getStatus(), PayErrorEnum.PAY_ORDER_PAY_FAILED.getCode() );
			throw new MallBusException(PayErrorEnum.PAY_ORDER_PAY_FAILED.getDesc(), PayErrorEnum.PAY_ORDER_PAY_FAILED.getCode());
		}
		
		
		//TODO 先将订单改为支付成功
		sinaOrder = sinaOrderDao.getOrderById(id);
		rows = sinaOrderDao.updateOrderBystatus(id, sinaOrder.getStatus(), PayOrderEnum.ALREADY_PAID.getStatus());
		if (1 != rows) {
			throw new MallBusException(PayErrorEnum.PAY_ORDER_PAY_FAILED.getDesc(), PayErrorEnum.PAY_ORDER_PAY_FAILED.getCode());
		}
		
		//TODO 开始扣除用户的余额 使用log日志模拟
		log.info("商户{}订单号{}支付成功，金额为{}", sinaOrder.getMerchantId(), sinaOrder.getOrderId(), sinaOrder.getOrderAmount());
		//TODO 调用异步通知
		SinaNotifyResponse snr = sinaNotify.sendNotify(sinaOrder);
		
		//将异步通知状态改为已通知
		sinaOrderDao.updateNotifyStatus(sinaOrder.getId(), sinaOrder.getNotifyStatus(), NotifyStatusEnum.已通知.getStatus());
		return snr;
	}
	
	private void orderExist(SinaOrder sinaOrder) {
		if (PayOrderEnum.ALREADY_PAID.getStatus() == sinaOrder.getStatus()) {
			throw new MallBusException(PayErrorEnum.ALREADY_PAY.getDesc(), PayErrorEnum.ALREADY_PAY.getCode());
		}
		
		if (PayOrderEnum.PAY_ING.getStatus() == sinaOrder.getStatus()) {
			throw new MallBusException(PayErrorEnum.PAY_ING.getDesc(), PayErrorEnum.PAY_ING.getCode());
		}
		
		if (PayOrderEnum.PAY_INVALID.getStatus() == sinaOrder.getStatus()) {
			throw new MallBusException(PayErrorEnum.PAY_INVALID.getDesc(), PayErrorEnum.PAY_INVALID.getCode());
		}
	}
	
	private SinaOrder orderNotExist(SinaPayRequest sinaPayRequest) {
		//订单不存在 入库
		SinaOrder sinaOrder = new SinaOrder();
		sinaOrder.setFee(fee);
		sinaOrder.setMerchantId(sinaPayRequest.getMerchantAcctId());
		sinaOrder.setMerchantName("大猿商城");
		sinaOrder.setNotifyMerchantUrl(sinaPayRequest.getBgUrl());
		sinaOrder.setNotifyStatus(NotifyStatusEnum.未通知.getStatus());
		sinaOrder.setNotifyTimes(0);
		sinaOrder.setOrderAmount(sinaPayRequest.getOrderAmount());
		sinaOrder.setPayAmount(sinaPayRequest.getOrderAmount());
		sinaOrder.setSignType(sinaPayRequest.getSignType());
		sinaOrder.setStatus(PayOrderEnum.UNPAID.getStatus());
		sinaOrder.setSynchMerchantUrl(sinaPayRequest.getBgUrl());
		sinaOrder.setOrderId(sinaPayRequest.getOrderId());
		sinaOrder.setOrderTime(DateUtil.stringToDate(sinaPayRequest.getOrderTime(), DateUtil.PATTERN_YYYYMMDDHHMMSS));
		
		int rows = sinaOrderDao.add(sinaOrder);
		if (1 != rows) {
			log.error("商户{}订单{}创建失败", sinaPayRequest.getMerchantAcctId(), sinaPayRequest.getOrderId());
			throw new MallBusException(PayErrorEnum.PAY_ORDER_CREATE_ERROR.getDesc(), PayErrorEnum.PAY_ORDER_CREATE_ERROR.getCode());
		}
		
		return sinaOrder;
	}

	@Override
	public SinaPayResponse getOrder(SinaPayQuery sinaPayQuery) {
		
		// 验证签名
		String origin = sinaPayQuery.createSignOrigin();
		String sign = null;
		if (SIGN_TYPE_MD5.equals(sinaPayQuery.getSignType())) {
			origin += key;
			sign = DigestUtils.md5Hex(origin);
		} else {
			//TODO DES生成签名
			sign = "xxxxxxxxxxxxxxxxxx";
		}
		
		if (StringUtils.isBlank(sign)) {
			throw new MallBusException(PayErrorEnum.SIGN_IS_EMPTY.getDesc(), PayErrorEnum.SIGN_IS_EMPTY.getCode());
		}
		
		if (!sign.equals(sinaPayQuery.getSignMsg())) {
			throw new MallBusException(PayErrorEnum.SIGN_VALUE_ERROR.getDesc(), PayErrorEnum.SIGN_VALUE_ERROR.getCode());
		}
		
		SinaOrder order = sinaOrderDao.getOrderByMerchantIdAndOrderId(sinaPayQuery.getMerchantId(), sinaPayQuery.getOrderId());
		if (null == order) {
			throw new MallBusException(PayErrorEnum.PAY_ORDER_UNEXIST.getDesc(), PayErrorEnum.PAY_ORDER_UNEXIST.getCode());
		}
		
		SinaPayResponse sr = SinaPayResponse.instance()
				.setDealId(String.valueOf(order.getId()))
				.setDealTime(DateUtil.dateToString(order.getModifyTime(), DateUtil.PATTERN_YYYYMMDDHHMMSS))
				.setFee(order.getFee())
				.setMerchantAcctId(order.getMerchantId())
				.setOrderAmount(order.getOrderAmount())
				.setOrderId(order.getOrderId())
				.setOrderTime(DateUtil.dateToString(order.getOrderTime(), DateUtil.PATTERN_YYYYMMDDHHMMSS))
				.setPayAmount(order.getPayAmount())
				.setPayResult("12");
		
		
		if (PayOrderEnum.ALREADY_PAID == PayOrderEnum.getPayStatus(order.getStatus())) {
			sr.setPayResult("10");
		}
		
		if (PayOrderEnum.PAY_FAILURE == PayOrderEnum.getPayStatus(order.getStatus())) {
			sr.setPayResult("11");
		}
		
		return sr;
	}

}
